#pragma once

#include <memory.h>
#include <AVUIObjectCollection.h>
#include <AVUIINotifyCollectionChanged.h>
#include <AVUIINotifyPropertyChanged.h>

namespace AVUI {

template <class T>
class ObservableCollection : public TObjectCollection<T>, public INotifyCollectionChanged, public INotifyPropertyChanged
{
public:

	IMPLEMENT_EVENT(CollectionChanged, CollectionChangedEventArgs)
	IMPLEMENT_EVENT(PropertyChanged, PropertyChangedEventArgs)
	IMPLEMENT_READONLY_VALUE_PROPERTY(Count, int, false)
    virtual Object* get_Object() { return Object::get_Object(); }

protected:

	virtual void ClearItems()
	{
		CheckReentrancy();
		TObjectCollection<T>::ClearItems();
		OnPropertyChanged(get_CountProperty());
		//OnPropertyChanged("Item[]");
		OnCollectionReset();
	}

	virtual void InsertItem(int index, T* pItem)
	{
		CheckReentrancy();
		TObjectCollection<T>::InsertItem(index, pItem);
		OnPropertyChanged(get_CountProperty());
		//OnPropertyChanged("Item[]");
		OnCollectionChanged(NotifyCollectionChangedAction::Add, pItem, index);
	}

	virtual void RemoveItem(int index)
	{
		CheckReentrancy();
		TRefCountedPtr<T> pItem = (*this)[index];
		TObjectCollection<T>::RemoveItem(index);
		OnPropertyChanged(get_CountProperty());
		//OnPropertyChanged("Item[]");
		OnCollectionChanged(NotifyCollectionChangedAction::Remove, pItem, index);
	}

	virtual void SetItem(int index, T* pItem)
	{
		CheckReentrancy();
		TRefCountedPtr<T> pOldItem = (*this)[index];
		TObjectCollection<T>::SetItem(index, pItem);
		//OnPropertyChanged("Item[]");
		OnCollectionChanged(NotifyCollectionChangedAction::Replace, pItem, pOldItem, index);
	}

	void CheckReentrancy() { }

	virtual void OnCollectionChanged(CollectionChangedEventArgs* pArgs)
	{
		invoke_CollectionChanged(this, pArgs);
	} 

	virtual void OnPropertyChanged(PropertyChangedEventArgs* pArgs)
	{
		invoke_PropertyChanged(this, pArgs);
	}

private:

	void OnCollectionChanged(NotifyCollectionChangedAction::Enum action, Object* pItem, int index)
	{
		CollectionChangedEventArgs ea(action, pItem, index);

		OnCollectionChanged(&ea);
	}

	void OnCollectionChanged(NotifyCollectionChangedAction::Enum action, Object* pItem, int index, int oldIndex)
	{
		CollectionChangedEventArgs ea(action, pItem, index, oldIndex);

		OnCollectionChanged(&ea);
	}

	void OnCollectionChanged(NotifyCollectionChangedAction::Enum action, Object* pOldItem, Object* pNewItem, int index)
	{
		CollectionChangedEventArgs ea(action, pOldItem, pNewItem, index);

		OnCollectionChanged(&ea);
	}

	void OnCollectionReset()
	{
		CollectionChangedEventArgs ea(NotifyCollectionChangedAction::Reset);

		OnCollectionChanged(&ea);
	}

	void OnPropertyChanged(Property* pProperty)
	{
		PropertyChangedEventArgs ea(pProperty);

		OnPropertyChanged(&ea);
	}

 

 


};

}; // namespace AVUI

